﻿using System;
using System.Collections.Generic;
using UFrame.PD;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor;

#endif

namespace UFrame
{
    /// <summary>
    /// 暂时不用
    /// </summary>
    public enum EResourceType
    {
    }


    public class PLResourceRequest
    {
        public EResourceType type;
        public System.Action<Object> onComplete;
        public ResourceRequest request;
    }


    public class ABInfo
    {
        public List<string> pathList;
        public string name;
    }

    /// <summary>
    /// 静态类 负责管理Unity中的AB包 和 资源
    /// </summary>
    public class ResourcesMa
    {
        /// <summary>
        /// AB名字找到AssetBundle
        /// </summary>
        public static Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();

        /// <summary>
        /// 存在当前内存中的AB包
        /// </summary>
        public static Dictionary<string, ABInfo> memoryABNameDic = new Dictionary<string, ABInfo>();

        /// <summary>
        /// 内存中存在的资源
        /// </summary>
        public static Dictionary<string, Object> allObjectDic = new Dictionary<string, Object>();


        /// <summary>
        /// 所有资源的路径,根据名字找到AB包
        /// </summary>
        public static Dictionary<string, string> globalPathABDic = new Dictionary<string, string>();


        public static string TestABPath = Application.dataPath + "/../AssetBundles/StandaloneWindows/";
        public static string EditorPath = Application.dataPath + "/bawAsset/";

        public static ELoadType loadType = ELoadType.Editor;

        /// <summary>
        /// 全部是异步
        /// </summary>
        public static bool isResourcesAsync = false;

        private static T InstanceObj<T>(T go) where T : Object
        {
            T instance = GameObject.Instantiate<T>(go);
            if (instance is GameObject)
            {
                GameObject g = instance as GameObject;
                g.transform.position = Vector3.zero;
            }

            return instance;
        }

        private static T ResourceLoad<T>(string path) where T : Object
        {
            T go = null;

            go = Resources.Load<T>(path);
            return go;
        }

        private static T ResourceLoadAsync<T>(string path, Action<T> loadComplete = null) where T : Object
        {
            T go = null;

            ResourceRequest rq = Resources.LoadAsync(path);
            PLResourceRequest pr = new PLResourceRequest();
            rq.completed += x => { };
            pr.request = rq;
            pr.onComplete = x =>
            {
                if (x == null)
                {
                    Debug.LogError("资源没有找到:" + path + " " + loadType);
                    loadComplete(null);
                    return;
                }

                var o = x as T;
                if (o == null)
                {
                    Debug.LogError(x + "转换: " + typeof(T).Name + "错误");
                }

                loadComplete(o);
            };
            CoroutineTool.I.AddPLResourceRequest(pr);

            return go;
        }


        private static T TestABLoad<T>(string path, Action<T> loadComplete = null) where T : Object
        {
            T go = null;
            path = path.ToLower();
            if (allObjectDic.ContainsKey(path))
            {
                go = allObjectDic[path] as T;
            }
            else
            {
                if (!globalPathABDic.ContainsKey(path))
                {
                    loadComplete(null);
                    return null;
                }

                string abName = globalPathABDic[path];
                if (isResourcesAsync) //异步
                {
                    var a = LoadABAsync(abName);
                    a.completed += operation =>
                    {
                        var o = a.assetBundle.LoadAsset<T>(path);
                        loadComplete(o);
                    };
                }
                else
                {
                    //同步直接加载AB包
                    go = LoadAB(abName, path) as T;
                }
            }

            return go;
        }

        public static T Load<T>(string path, Action<T> loadComplete = null) where T : Object
        {
            return Load(path, false, loadComplete);
        }

        public static T LoadSprite<T>(string path, string name, Action<T> loadComplete = null) where T : Object
        {
            SpriteAtlas s = Load<SpriteAtlas>(path, false);
            Sprite sprite = s.GetSprite(name);
            return sprite as T;
        }

        public static void LoadSpriteAsync<T>(string path, string name, Action<T> loadComplete = null) where T : Object
        {
            SpriteAtlas s = Load<SpriteAtlas>(path, false,
                atlas => { loadComplete(atlas.GetSprite(name) as T); });
        }


        public static T Load<T>(string path, bool isInstantiate, Action<T> loadComplete = null) where T : Object
        {
            T go = null;

            switch (loadType)
            {
                case ELoadType.AB:
                    throw new NotImplementedException("没有实现AB包加载方式");
                    break;
                case ELoadType.Editor:
#if UNITY_EDITOR
                    go = AssetDatabase.LoadAssetAtPath<T>(path);
#endif
                    break;
                case ELoadType.Resource:
                    if (path.LastIndexOf(".") > 0)
                    {
                        path = path.Substring(0, path.LastIndexOf("."));
                    }

                    go = ResourceLoad<T>(path);
                    break;
                case ELoadType.TestAB:
                    go = TestABLoad(path, loadComplete);
                    break;
                default:
                    Debug.LogError(loadType);
                    break;
            }

            if (go == null)
            {
                Debug.LogError("资源没有找到:" + path + " " + loadType);
            }
            else
            {
                if (isInstantiate)
                {
                    go = InstanceObj<T>(go);
                }
            }


            if (loadComplete != null)
            {
                loadComplete(go);
            }

            return go;
        }

        public static void AddObject(string abName, string path, Object o)
        {
            allObjectDic.Add(path, o);
            memoryABNameDic[abName].pathList.Add(path);
            globalPathABDic.Add(path,abName);
        }


        public static void DeleteMemoryAB(string abName)
        {
            if (!memoryABNameDic.ContainsKey(abName))
            {
                return;
            }

            var info = memoryABNameDic[abName];
            Object o = null;
            foreach (var path in info.pathList)
            {
                o = allObjectDic[path];
                GameObject.DestroyImmediate(o);
                Resources.UnloadAsset(o);
                allObjectDic.Remove(path);
            }

            memoryABNameDic.Remove(abName);
        }

        public static AssetBundle LoadAB(string abName)
        {
            string path = GetPath(abName);
            if (path == null)
            {
                return null;
            }

            AssetBundle ab = AssetBundle.LoadFromFile(path);
            ABInfo abInfo = new ABInfo();
            abInfo.name = abName;
            memoryABNameDic.Add(abName, abInfo);
            return ab;
        }

        public static Object LoadAB(string abName, string resName)
        {
            var ab = LoadAB(abName);
            Object ot = ab.LoadAsset(resName);
            AddObject(abName, resName, ot);
            return ot;
        }

        public static AssetBundleCreateRequest LoadABAsync(string abName)
        {
            string path = GetPath(abName);
            if (path == null)
            {
                return null;
            }

            AssetBundleCreateRequest abq = AssetBundle.LoadFromFileAsync(path);
            abq.completed += operation =>
            {
                if (operation.isDone)
                {
                    ABInfo abInfo = new ABInfo();
                    abInfo.name = abq.assetBundle.name;
                    memoryABNameDic.Add(abInfo.name, abInfo);
                }
                else
                {
                    Debug.LogError("加载出错: " + path);
                }
            };
            return abq;
        }

        public static string GetPath(string name)
        {
            switch (GameConfig.I.loadType)
            {
                case ELoadType.AB:
                    return name;
                case ELoadType.Editor:
                    return EditorPath + name;
                case ELoadType.Resource:
                    return name;
                case ELoadType.TestAB:
                    return TestABPath + name;
            }

            return name;
        }
    }
}